/* $Id: callbacks.c,v 1.11 2006/12/30 19:21:04 bhepple Exp $ */

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <gnome.h>
#include <ctype.h>

#include "callbacks.h"
#include "interface.h"
#include "support.h"
#include "dcalc.h"
#include "main.h"

void
on_exit_activate                       (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
  process(QUIT);
}

void
on_edit_activate                       (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
}

void
on_settings_activate                   (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
}

void
on_degree_activate                     (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
  process(DEGREE);
}

void
on_radians_activate                    (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
  process(RADIAN);
}

void
on_scientific_mode_activate            (GtkMenuItem     *menuitem,
										gpointer         user_data)
{
  process(SCI);
  display_buttons(SCI);
}

void
on_financial_mode_activate             (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
  process(FIN);
  display_buttons(FIN);
}

void
on_statistics_mode_activate            (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
  process(STAT);
  display_buttons(STAT);
}

void
on_programming_mode_activate           (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
  process(PROG);
  display_buttons(PROG);
}

void
on_convert_activate                    (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
}

#define ENTRYSIZE 25

struct assoc_s {
	char *name;
	char *value;
};
typedef struct assoc_s *assoc;
static assoc *assocList = NULL;

static assoc *getNextNameValue(assoc *p, char *name, char *value) {
    assoc *a = (assoc *) p;
    if (a == NULL)
		a = assocList;
    else
		a++;

    if (a == NULL || *a == NULL)
		return NULL;

	strcpy(name, (*a)->name);
	strcpy(value, (*a)->value);
    return a;
}

static char *getNameString(char *name) {
    assoc *a;

    if (assocList == NULL) {
	assocList = malloc(sizeof(assoc));
	*assocList = NULL;
    }
    for (a = assocList; *a != NULL; a++)
	if (strcmp((*a)->name, name) == 0)
	    return((*a)->value);
    return "";
}

static void saveNameString(char *name, char *value) {
    assoc *a;
    int listSize = 0;

    if (assocList == NULL) {
	assocList = malloc(sizeof(assoc));
	*assocList = NULL;
    }
    for (a = assocList; *a != NULL; a++) {
	listSize++;
	if (strcmp((*a)->name, name) == 0) {
	    (*a)->value = realloc((*a)->value, strlen(value) + 1);
	    strcpy((*a)->value, value);
	    return;
	}
    }
    listSize++;
    assocList = realloc(assocList, sizeof(assoc) * (listSize + 1));
    assocList[listSize] = NULL;
    a = assocList + listSize - 1;
    *a = assocList[listSize - 1] = malloc(sizeof(struct assoc_s));
    (*a)->name = strdup(name);
    (*a)->value = strdup(value);
}

void readGuiSettings(char *b) {
	char *name, *value;

	name = b;
	while (*b && !isspace(*b))
		b++;
	*b++ = 0;
	if (*b) {
		if (strcmp(name, "registers") == 0) {
			registers = (GtkWidget *) atoi(b); /* I know, it's a clunker, but it works */
#ifdef RUNTIME_FONT_CHANGES_ARE_WORKING
		} else if (strcmp(name, "numberfont") == 0) {
			strcpy(calculatorFont, b);
			fixFont(calculatorFont, main_window, "entry_X");
			fixFont(calculatorFont, main_window, "entry_Y");
			fixFont(calculatorFont, main_window, "entry_Z");
			fixFont(calculatorFont, main_window, "entry_T");
			fixFont(calculatorFont, main_window, "entry_L");
		} else if (strcmp(name, "buttonfont") == 0) {
			strcpy(buttonFont, b);
			setButtonFont(buttonFont);
		} else if (strcmp(name, "plusminusfont") == 0) {
			strcpy(plusMinusFont, b);
			setPlusMinusFont(plusMinusFont);
#endif
		} else {
			value = b;
			saveNameString(name, value);
		}
	}
}

void saveGuiSettings(FILE *f) {
	assoc *a = NULL;
	char name[ENTRYSIZE], value[ENTRYSIZE];

	if (f) {
		while ((a = getNextNameValue(a, name, value)) != NULL)
			fprintf(f, "gui %s %s\n", name, value);
		fprintf(f, "gui registers %d\n", registers? 1: 0);
#ifdef RUNTIME_FONT_CHANGES_ARE_WORKING
		fprintf(f, "gui numberfont %s\n", calculatorFont);
		fprintf(f, "gui buttonfont %s\n", buttonFont);
		fprintf(f, "gui plusminusfont %s\n", plusMinusFont);
#endif
	}
}

static int doConvert(char table[][ENTRYSIZE],
					  char *title,
					  char *pFrom,
					  char *pTo) {
	GtkWidget *convert_dialog;
	GtkLabel *convert_label;
	GList *combo_items = NULL;
	GtkCombo *from_combo, *to_combo;
	int		i, reply, retval = 1;
	const char const  *from, *to;

    msg("");
	convert_dialog = create_convert();

	if (strlen(pFrom))
		combo_items = g_list_append (combo_items, pFrom);
	for (i = 0; *table[i] != 0; i++)
		combo_items = g_list_append (combo_items, table[i]);
	from_combo = gtk_object_get_data(GTK_OBJECT (convert_dialog), "convert_from_combo");
	gtk_combo_set_popdown_strings (GTK_COMBO (from_combo), combo_items);
	g_list_free(combo_items);

	combo_items = NULL;
	if (strlen(pTo))
		combo_items = g_list_append (combo_items, pTo);
	for (i = 0; *table[i] != 0; i++)
		combo_items = g_list_append (combo_items, table[i]);
	to_combo =   gtk_object_get_data(GTK_OBJECT (convert_dialog), "convert_to_combo");
	gtk_combo_set_popdown_strings (GTK_COMBO (to_combo), combo_items);
	g_list_free(combo_items);
	combo_items = NULL;

	convert_label = gtk_object_get_data(GTK_OBJECT (convert_dialog), "convert_label");
	gtk_label_set_text(convert_label, title);

	reply = gtk_dialog_run(GTK_DIALOG(convert_dialog));
	from = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(from_combo)->entry));
	to   = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(to_combo)->entry));
	strcpy(pFrom, from);
	strcpy(pTo, to);
	if (reply == 0)
		convertX(from, to);
	else if (reply == 1)
		convertX(to, from);
	else
		retval = 0;

	gtk_widget_destroy(convert_dialog);
	return retval;
}

void
on_length_activate                     (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	char table[][ENTRYSIZE] = {
		"mile",
		"nautical mile",
		"furlong",
		"chain",
		"yard",
		"feet",
		"inch",
		"thou",
		"kilometer",
		"metre",
		"cm",
		"mm",
		"micron",
		"",
	};
	char from[ENTRYSIZE], to[ENTRYSIZE];

	strcpy(from, getNameString("LengthConversionFrom"));
	strcpy(to, getNameString("LengthConversionTo"));
	if (doConvert(table, "Length Conversion", from, to)) {
		saveNameString("LengthConversionFrom", from);
		saveNameString("LengthConversionTo", to);
	}
}

void
on_area_activate(GtkMenuItem     *menuitem,
				 gpointer         user_data)
{
	char table[][ENTRYSIZE] = {
		"mile^2",
		"acre",
		"yard^2",
		"feet^2",
		"inch^2",
		"km^2",
		"hectare",
		"metres^2",
		"cm^2",
		"mm^2",
		""
	};
	char from[ENTRYSIZE], to[ENTRYSIZE];

	strcpy(from, getNameString("AreaConversionFrom"));
	strcpy(to, getNameString("AreaConversionTo"));
	if (doConvert(table, "Area conversion", from, to)) {
		saveNameString("AreaConversionFrom", from);
		saveNameString("AreaConversionTo", to);
	}
}

void
on_volume_activate(GtkMenuItem     *menuitem,
				   gpointer         user_data)
{
	char table[][ENTRYSIZE] = {
		"br gallons",
		"br pints",
		"gallons",
		"pints",
		"feet^3",
		"inches^3",
		"fluid ounce",
		"metre^3",
		"litres",
		"cc",
		""
	};
	char from[ENTRYSIZE], to[ENTRYSIZE];

	strcpy(from, getNameString("VolumeConversionFrom"));
	strcpy(to, getNameString("VolumeConversionTo"));
	if (doConvert(table, "Volume conversion", from, to)) {
		saveNameString("VolumeConversionFrom", from);
		saveNameString("VolumeConversionTo", to);
	}

}

void
on_mass_activate                       (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	char table[][ENTRYSIZE] = {
		"tons",
		"cwts",
		"stones",
		"pounds",
		"ounces",
		"grains",
		"tonnes",
		"kg",
		"grams",
		""
	};
	char from[ENTRYSIZE], to[ENTRYSIZE];

	strcpy(from, getNameString("MassConversionFrom"));
	strcpy(to, getNameString("MassConversionTo"));
	if (doConvert(table, "Mass conversion", from, to)) {
		saveNameString("MassConversionFrom", from);
		saveNameString("MassConversionTo", to);
	}

}

void
on_speed_activate                      (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	char table[][ENTRYSIZE] = {
		"knots",
		"mph",
		"feet/s",
		"kph",
		"meters/s",
		""
	};
	char from[ENTRYSIZE], to[ENTRYSIZE];

	strcpy(from, getNameString("SpeedConversionFrom"));
	strcpy(to, getNameString("SpeedConversionTo"));
	if (doConvert(table, "Speed conversion", from, to)) {
		saveNameString("SpeedConversionFrom", from);
		saveNameString("SpeedConversionTo", to);
	}

}

void
on_fuel_activate                       (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	char table[][ENTRYSIZE] = {
		"miles / gallon",
		"miles / br gallon",
		"litres/100 km",
		""
	};
	char from[ENTRYSIZE], to[ENTRYSIZE];

	strcpy(from, getNameString("FuelConversionFrom"));
	strcpy(to, getNameString("FuelConversionTo"));
	if (doConvert(table, "Fuel conversion", from, to)) {
		saveNameString("FuelConversionFrom", from);
		saveNameString("FuelConversionTo", to);
	}

}

void
on_pressure_activate                   (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	char table[][ENTRYSIZE] = {
		"atmospheres",
		"psi",
		"millibars",
		"mm Hg",
		"pascals",
		""
	};
	char from[ENTRYSIZE], to[ENTRYSIZE];

	strcpy(from, getNameString("PressureConversionFrom"));
	strcpy(to, getNameString("PressureConversionTo"));
	if (doConvert(table, "Convert pressure", from, to)) {
		saveNameString("PressureConversionFrom", from);
		saveNameString("PressureConversionTo", to);
	}

}

void
on_temperature_activate                (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	char table[][ENTRYSIZE] = {
		"deg fahrenheit",
		"deg celsius",
		"deg kelvin",
		""
	};
	char from[ENTRYSIZE], to[ENTRYSIZE];

	strcpy(from, getNameString("TempConversionFrom"));
	strcpy(to, getNameString("TempConversionTo"));
	if (doConvert(table, "Convert temperature range", from, to)) {
		saveNameString("TempConversionFrom", from);
		saveNameString("TempConversionTo", to);
	}

}

void
on_currency_activate                   (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{

	char table[][ENTRYSIZE] = {
		"australia dollar",
		"newzealand dollar",
		"united kingdom pound",
		"united states dollar",
		"- Europe -",
		"austria schilling",
		"belgium franc",
		"britain pound",
		"czechko runa",
		"denmark krone",
		"euro",
		"finland markka",
		"france franc",
		"germany mark",
		"great britain pound",
		"greece drachma",
		"hungary forint",
		"ireland punt",
		"israel shekel",
		"italy lira",
		"netherlands guilder",
		"norway krone",
		"poland zloty",
		"portugal escudo",
		"russia ruble",
		"slovakia koruna",
		"south africa rand",
		"spain peseta",
		"sweden krona",
		"switzerland franc",
		"united kingdom pound",
		"- Asia -",

		"china yuan",
		"hongkong dollar",
		"india rupee",
		"indonesia rupiah",
		"japan yen",
		"malaysia ringgit",
		"pakistan rupee",
		"philippines peso",
		"singapore dollar",
		"south korea won",
		"taiwan dollar",
		"thailand baht",
		"- Middle East -",

		"egypt pound",
		"jordan dinar",
		"lebanon pound",
		"saudi arabia riyal",
		"turkey lira",
		"united arab dirham",
		"- America -",
		"argentina peso",
		"brazil real",
		"canada dollar",
		"chile peso",
		"colombia peso",
		"ecuador sucre",
		"mexico peso",
		"peru new sol",
		"united states dollar",
		"uruguay new peso",
		"venezuela bolivar",
		""
	};
	char from[ENTRYSIZE], to[ENTRYSIZE];

	strcpy(from, getNameString("MoneyConversionFrom"));
	strcpy(to, getNameString("MoneyConversionTo"));
	if (doConvert(table, "Convert currency", from, to)) {
		saveNameString("MoneyConversionFrom", from);
		saveNameString("MoneyConversionTo", to);
	}

}

void
on_other_activate                     (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{

	char table[][ENTRYSIZE] = {

		""
	};
	char from[ENTRYSIZE], to[ENTRYSIZE];

	strcpy(from, getNameString("OtherConversionFrom"));
	strcpy(to, getNameString("OtherConversionTo"));
	if (doConvert(table, "Convert more or less anything (see units(1))", from, to)) {
		saveNameString("OtherConversionFrom", from);
		saveNameString("OtherConversionTo", to);
	}
}

void
on_help_activate                       (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{

}

void
on_documentation_activate              (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{

}

void
on_about_activate                      (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
  GtkWidget *about;
  int reply;

  about = create_about ();
  reply = gtk_dialog_run(GTK_DIALOG(about));
  gtk_widget_destroy(about);
}

#define LCLICK(x,y) void on_L ## x ## _ ## y ## _clicked \
	(GtkButton *button, gpointer user_data) \
{ process(button_command(l_buttons, x, y)); }

LCLICK(0,0)
LCLICK(0,1)
LCLICK(0,2)
LCLICK(0,3)
LCLICK(0,4)
LCLICK(0,5)
LCLICK(0,6)
LCLICK(0,7)

LCLICK(1,0)
LCLICK(1,1)
LCLICK(1,2)
LCLICK(1,3)
LCLICK(1,4)
LCLICK(1,5)
LCLICK(1,6)
LCLICK(1,7)

LCLICK(2,0)
LCLICK(2,1)
LCLICK(2,2)
LCLICK(2,3)
LCLICK(2,4)
LCLICK(2,5)
LCLICK(2,6)
LCLICK(2,7)

void
on_R0_0_clicked                        (GtkButton       *button,
                                        gpointer         user_data)
{
	int b = button_command(r_buttons, 0, 0);
	GtkWidget *w;

	w = gtk_object_get_data(GTK_OBJECT(main_window), 
							(b==SCI)? "scientific_mode":
							(b==FIN)? "financial_mode":
							(b==STAT)? "statistics_mode":
							"programming_mode");
	if (w)
		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w), 1);
	else
		fprintf(stderr, "gdcalc: Can't find main mode item in menu\n");
}

void
on_R0_1_clicked                        (GtkButton       *button,
                                        gpointer         user_data)
{
	int b = button_command(r_buttons, 0, 1);
	GtkWidget *w;

	w = gtk_object_get_data(GTK_OBJECT(main_window), 
							(b==SCI)? "scientific_mode":
							(b==FIN)? "financial_mode":
							(b==STAT)? "statistics_mode":
							"programming_mode");
	if (w)
		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w), 1);
	else
		fprintf(stderr, "gdcalc: Can't find main mode item in menu\n");
}

void
on_R0_2_clicked                          (GtkButton       *button,
                                        gpointer         user_data)
{
	int b = button_command(r_buttons, 0, 2);
	GtkWidget *w;

	w = gtk_object_get_data(GTK_OBJECT(main_window), 
							(b==SCI)? "scientific_mode":
							(b==FIN)? "financial_mode":
							(b==STAT)? "statistics_mode":
							"programming_mode");
	if (w)
		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w), 1);
	else
		fprintf(stderr, "gdcalc: Can't find main mode item in menu\n");
}

#define RCLICK(x,y) void on_R ## x ## _ ## y ## _clicked \
	(GtkButton *button, gpointer user_data) \
{ process(button_command(r_buttons, x, y)); }

RCLICK(0,3)
RCLICK(0,4)
RCLICK(0,5)
RCLICK(1,0)
RCLICK(1,1)
RCLICK(1,2)
RCLICK(1,3)
RCLICK(1,4)
RCLICK(1,5)
RCLICK(2,0)
RCLICK(2,1)
RCLICK(2,2)
RCLICK(2,3)
RCLICK(2,4)
RCLICK(2,5)
RCLICK(3,0)
RCLICK(3,1)
RCLICK(3,2)
RCLICK(3,3)
RCLICK(3,4)
RCLICK(3,5)
RCLICK(4,0)
RCLICK(4,1)
RCLICK(4,2)
RCLICK(4,3)
RCLICK(4,4)
RCLICK(4,5)
RCLICK(5,0)
RCLICK(5,1)
RCLICK(5,2)
RCLICK(5,3)
RCLICK(5,4)
RCLICK(5,5)

void
on_Minus_clicked                       (GtkButton       *button,
                                        gpointer         user_data)
{
	if (algebraic_mode) {
		if (liftStack()) {
			set_x("ans ");
		}
		append_x("-");
	} else
		process(MINUS);

}

void
on_Mult_clicked                        (GtkButton       *button,
                                        gpointer         user_data)
{
	if (algebraic_mode) {
		if (liftStack()) {
			set_x("ans ");
		}
		append_x("*");
	} else
		process(MULT);

}

void
on_Divide_clicked                      (GtkButton       *button,
                                        gpointer         user_data)
{
	if (algebraic_mode) {
		if (liftStack()) {
			set_x("ans ");
		}
		append_x("/");
	} else
		process(DIVIDE);

}

void
on_Plus_clicked                        (GtkButton       *button,
                                        gpointer         user_data)
{
	if (algebraic_mode) {
		if (liftStack()) {
			set_x("ans ");
		}
		append_x("+");
	} else
		process(PLUS);
}

void
on_Enter_clicked                       (GtkButton       *button,
                                        gpointer         user_data)
{
  process(ENTER);

}

void
on_LeftBrace_clicked                   (GtkButton       *button,
                                        gpointer         user_data)
{
	if (liftStack()) {
		set_x("");
	}
	append_x("(");
}


void
on_RightBrace_clicked                  (GtkButton       *button,
                                        gpointer         user_data)
{
	if (liftStack()) {
		set_x("");
	}
	append_x(")");
}


void
on_Equals_clicked                      (GtkButton       *button,
                                        gpointer         user_data)
{
	strcpy(last_eval, get_x());
	if (mode == PROG)
		pop();
	else
		popf();;
	process(EQUALS);
}


void
on_places_ok_clicked                   (GtkButton       *button,
                                        gpointer         user_data)
{

}

void
on_places_cancel_clicked               (GtkButton       *button,
                                        gpointer         user_data)
{

}

void
on_convert_ok_clicked                  (GtkButton       *button,
                                        gpointer         user_data)
{

}

void
on_convert_reverse_clicked             (GtkButton       *button,
                                        gpointer         user_data)
{

}

void
on_convert_cancel_clicked              (GtkButton       *button,
                                        gpointer         user_data)
{

}

void
on_about_ok_clicked                    (GtkButton       *button,
                                        gpointer         user_data)
{

}

void
on_dialog_ok_clicked                   (GtkButton       *button,
                                        gpointer         user_data)
{
}

void
on_dialog_cancel_clicked               (GtkButton       *button,
                                        gpointer         user_data)
{
}


void
on_mem_cancel_clicked                  (GtkButton       *button,
                                        gpointer         user_data)
{

}

gboolean
on_mem0_button_release_event           (GtkWidget       *widget,
                                        GdkEventButton  *event,
                                        gpointer         user_data)
{
  mem_value = 0;
  gtk_widget_destroy(mem_dialog);

  return FALSE;
}

gboolean
on_mem1_button_release_event           (GtkWidget       *widget,
                                        GdkEventButton  *event,
                                        gpointer         user_data)
{
  mem_value = 1;
  gtk_widget_destroy(mem_dialog);

  return FALSE;
}

gboolean
on_mem2_button_release_event           (GtkWidget       *widget,
                                        GdkEventButton  *event,
                                        gpointer         user_data)
{
  mem_value = 2;
  gtk_widget_destroy(mem_dialog);

  return FALSE;
}

gboolean
on_mem3_button_release_event           (GtkWidget       *widget,
                                        GdkEventButton  *event,
                                        gpointer         user_data)
{
  mem_value = 3;
  gtk_widget_destroy(mem_dialog);

  return FALSE;
}

gboolean
on_mem4_button_release_event           (GtkWidget       *widget,
                                        GdkEventButton  *event,
                                        gpointer         user_data)
{
  mem_value = 4;
  gtk_widget_destroy(mem_dialog);

  return FALSE;
}

gboolean
on_mem5_button_release_event           (GtkWidget       *widget,
                                        GdkEventButton  *event,
                                        gpointer         user_data)
{
  mem_value = 5;
  gtk_widget_destroy(mem_dialog);

  return FALSE;
}

gboolean
on_mem6_button_release_event           (GtkWidget       *widget,
                                        GdkEventButton  *event,
                                        gpointer         user_data)
{
  mem_value = 6;
  gtk_widget_destroy(mem_dialog);

  return FALSE;
}

gboolean
on_mem7_button_release_event           (GtkWidget       *widget,
                                        GdkEventButton  *event,
                                        gpointer         user_data)
{
  mem_value = 7;
  gtk_widget_destroy(mem_dialog);

  return FALSE;
}

gboolean
on_mem8_button_release_event           (GtkWidget       *widget,
                                        GdkEventButton  *event,
                                        gpointer         user_data)
{
  mem_value = 8;
  gtk_widget_destroy(mem_dialog);

  return FALSE;
}

gboolean
on_mem9_button_release_event           (GtkWidget       *widget,
                                        GdkEventButton  *event,
                                        gpointer         user_data)
{
  mem_value = 9;
  gtk_widget_destroy(mem_dialog);

  return FALSE;
}

static void
do_copy() {
	gtk_signal_emit_by_name( GTK_OBJECT(entryX), "copy-clipboard");
}

static void
do_paste() {
	gtk_signal_emit_by_name( GTK_OBJECT(entryX), "paste-clipboard");
}

gboolean
on_main_window_key_press_event         (GtkWidget       *widget,
                                        GdkEventKey     *event,
                                        gpointer         user_data)
{
	int inval;

	/*
	printf("main_window got ");
	if (event->state & GDK_SHIFT_MASK)
		printf("S-");
	if (event->state & GDK_CONTROL_MASK)
		printf("C-");
	if (event->state & GDK_MOD1_MASK)
		printf("A-");
	if (event->state & GDK_MOD2_MASK)
		printf("M-");
	if (event->keyval >= 0x20 && event->keyval<=0xff)
		printf("%c", event->keyval);
	else
		printf("0x%x", event->keyval);
	printf("\n");
	*/
	inval = event->keyval;

	/* raw_mode: process the keycode & eat the event */
	if (event->state & GDK_CONTROL_MASK) {
		if (inval >= 'a' && inval <= 'z')
			inval -= 0x20;
		inval -= 0x40;
	}

	if (event->state & GDK_MOD1_MASK)
		inval |= 0x80;

	if (mode == PROG && intmode == ASCIIM) {
		switch (inval) {
		case GDK_Escape:    	inval = 27; break;
		case GDK_KP_Enter:
		case GDK_Return:		inval = 10; break;
		case GDK_Tab:	    	inval = 9;  break;
		case GDK_BackSpace: 	inval = 8;  break;
		case GDK_KP_Add:		inval = '+'; break;
		case GDK_KP_Subtract:	inval = '-'; break;
		case GDK_KP_Multiply:	inval = '*'; break;
		case GDK_KP_Divide:		inval = '/'; break;
		default:	break;
		}
	} else {
		inval = toupper(inval);
		switch (inval) {
		case GDK_KP_Enter:
		case GDK_Return:
		case '=':
		case 10:	if (algebraic_mode) inval = EQUALS; else inval = ENTER;		break;

		case 3:		/* ^c - copy X to clipboard */
			do_copy();
			inval = NOP;
			break;
		case 22:	/* ^v - paste from clipboard to X */
			do_paste();
			inval = NOP;
			break;
		case 17:	/* ^q - quit */
			inval = QUIT;
			break;
		default:	
			if (!algebraic_mode)
				switch (inval) {
				case '+':	inval = PLUS;		break;
				case '-':	inval = MINUS;		break;
				case '*':	inval = MULT;		break;
				case '/':	inval = DIVIDE;		break;
				case '%':	inval = PERCENT;	break;
				case 'p':	inval = PI;			break;
				case '^':	inval = YTOX;		break;
				case '&':	inval = dAND;		break;
				case '|':	inval = dOR;		break;
				case '~':	inval = dNOT;		break;
				case '<':	inval = SHIFTL;		break;
				case '>':	inval = SHIFTR;		break;
				case ',':	inval = CHS;		break;
				}
			break;
		}
	}

	/* map input characters to commands */
	switch(inval) {
	case GDK_Escape:    	inval = INV; break;
	case GDK_Tab:	    	inval = 9;  break;
	case GDK_Up:
	case GDK_Page_Up:		inval = ENTER; break;
	case GDK_Down:
	case GDK_Page_Down:		inval = ROLLDOWN; break;

	default:	
		if (!algebraic_mode)
			switch(inval) {
			case GDK_Left:
			case GDK_BackSpace: 	inval = 8;  break;
			case GDK_KP_Add:		inval = PLUS; break;
			case GDK_KP_Subtract:	inval = MINUS; break;
			case GDK_KP_Multiply:	inval = MULT; break;
			case GDK_KP_Divide:		inval = DIVIDE; break;
			case GDK_KP_Insert:
			case GDK_KP_0:			inval = '0'; break;
			case GDK_KP_End:
			case GDK_KP_1:			inval = '1'; break;
			case GDK_KP_Down:
			case GDK_KP_2:			inval = '2'; break;
			case GDK_KP_Page_Down:
			case GDK_KP_3:			inval = '3'; break;
			case GDK_KP_Left:
			case GDK_KP_4:			inval = '4'; break;
			case GDK_KP_Begin:
			case GDK_KP_5:			inval = '5'; break;
			case GDK_KP_Right:
			case GDK_KP_6:			inval = '6'; break;
			case GDK_KP_Home:
			case GDK_KP_7:			inval = '7'; break;
			case GDK_KP_Up:
			case GDK_KP_8:			inval = '8'; break;
			case GDK_KP_Page_Up:
			case GDK_KP_9:			inval = '9'; break;
			case GDK_KP_Delete:
			case GDK_KP_Decimal:	inval = '.'; break;
				/* ignore these: */
			case GDK_Shift_L:
			case GDK_Shift_R:
			case GDK_Control_L:
			case GDK_Control_R:
			case GDK_Meta_L:
			case GDK_Meta_R:
			case GDK_Alt_L:
			case GDK_Alt_R:
			case GDK_Num_Lock:
			case GDK_Caps_Lock:
			case GDK_Shift_Lock:
				return TRUE;
			}
		break;
	}

	if (algebraic_mode) {
		switch (inval) {
		case PERCENT:
			append_x("%");
		case EQUALS:
			last_was_fin_key = 0;
			gtk_signal_emit_stop_by_name(GTK_OBJECT (widget), "key_press_event");
			on_Equals_clicked(NULL, NULL);
			return TRUE;
			
			/* These needY: */
		case COMB:
		case DIVIDE12:
		case DIVIDE:
		case DYS:
		case SHIFTL:
		case SHIFTR:
		case SHIFTYL:
		case SHIFTYR:
		case MINUS:
		case MULT:
		case PERM:
		case PLUS:
		case RTOP:
		case SQR:
		case TIMES12:
		case YTOX:
		case dAND:
		case dOR:
		case dXOR:
			do {	
				char retval[2];
				if (liftStack()) {
					set_x("ans ");
				}
				retval[0] = inval;
				retval[1] = 0;
				/* append_x(retval); */
				return TRUE;
			} while (0);
		default:
			if (liftStack()) {
				set_x("");
			}
			last_was_fin_key = 0;
			return FALSE; /* ... just echo to the buffer */
		}
	} else {
		gtk_signal_emit_stop_by_name(GTK_OBJECT (widget), "key_press_event");
		process(inval);
	}
	return TRUE;
}

void
close_registers(GtkButton       *button,
				gpointer         user_data) {
	/* this rather assumes that they're on ... */
	toggle_registers();
}

void
on_register_window_activate(GtkMenuItem     *menuitem,
							gpointer         user_data) {
	toggle_registers();
}

static GtkWidget *font_dialog;
static GtkWidget *button_font_dialog;
static GtkWidget *plusminus_font_dialog;

void
on_font_activate                       (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	GnomeFontPicker *gfp;

	font_dialog = create_font_dialog();

	gfp = GNOME_FONT_PICKER(gtk_object_get_data(GTK_OBJECT (font_dialog), "fontpicker"));
	gnome_font_picker_set_font_name(gfp, calculatorFont);
	gtk_widget_show(font_dialog);
}

void
on_font_apply_clicked                  (GtkButton       *button,
                                        gpointer         user_data)
{
#ifdef RUNTIME_FONT_CHANGES_ARE_WORKING
	GnomeFontPicker *gfp;

	gfp = GNOME_FONT_PICKER(gtk_object_get_data(GTK_OBJECT (font_dialog), "fontpicker"));

	if (gfp == NULL)
		msg("Can't find fontpicker");
	else {
		strcpy(calculatorFont, gnome_font_picker_get_font_name(gfp));
		fixFont(calculatorFont, main_window, "entry_X");
		fixFont(calculatorFont, main_window, "entry_Y");
		fixFont(calculatorFont, main_window, "entry_Z");
		fixFont(calculatorFont, main_window, "entry_T");
		fixFont(calculatorFont, main_window, "entry_L");
		gtk_widget_draw(main_window, NULL);
	}
#endif
}

void
on_font_ok_clicked                  (GtkButton       *button,
									 gpointer         user_data)
{
	on_font_apply_clicked(button, user_data);
	gtk_widget_destroy(font_dialog);
}

void
on_font_cancel_clicked                  (GtkButton       *button,
										 gpointer         user_data)
{
	gtk_widget_destroy(font_dialog);
}

void
on_button_font_activate                (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	GnomeFontPicker *gfp;

	button_font_dialog = create_button_font_dialog();

	gfp = GNOME_FONT_PICKER(gtk_object_get_data(GTK_OBJECT (button_font_dialog), "buttonfontpicker"));
	gnome_font_picker_set_font_name(gfp, buttonFont);
	gtk_widget_show(button_font_dialog);

}


void
on_button_font_apply_clicked                  (GtkButton       *button,
                                        gpointer         user_data)
{
#ifdef RUNTIME_FONT_CHANGES_ARE_WORKING
	GnomeFontPicker *gfp;

	gfp = GNOME_FONT_PICKER(gtk_object_get_data(GTK_OBJECT (button_font_dialog), "buttonfontpicker"));

	if (gfp == NULL)
		msg("Can't find buttonfontpicker");
	else {
		strcpy(buttonFont, gnome_font_picker_get_font_name(gfp));
		setButtonFont(buttonFont);
		gtk_widget_draw(main_window, NULL);
	}
#endif
}

void
on_button_font_ok_clicked                  (GtkButton       *button,
									 gpointer         user_data)
{
	on_button_font_apply_clicked(button, user_data);
	gtk_widget_destroy(button_font_dialog);
}

void
on_button_font_cancel_clicked                  (GtkButton       *button,
										 gpointer         user_data)
{
	gtk_widget_destroy(button_font_dialog);
}

void
on_plus_minus_font_activate            (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	GnomeFontPicker *gfp;

	plusminus_font_dialog = create_plusminus_font_dialog();

	gfp = GNOME_FONT_PICKER(gtk_object_get_data(GTK_OBJECT (plusminus_font_dialog), "plusminusfontpicker"));
	gnome_font_picker_set_font_name(gfp, plusMinusFont);
	gtk_widget_show(plusminus_font_dialog);

}

void
on_plusminus_font_apply_clicked                  (GtkButton       *button,
                                        gpointer         user_data)
{
#ifdef RUNTIME_FONT_CHANGES_ARE_WORKING
	GnomeFontPicker *gfp;

	gfp = GNOME_FONT_PICKER(gtk_object_get_data(GTK_OBJECT (plusminus_font_dialog), "plusminusfontpicker"));

	if (gfp == NULL)
		msg("Can't find plusminusfontpicker");
	else {
		strcpy(plusMinusFont, gnome_font_picker_get_font_name(gfp));
		setPlusMinusFont(plusMinusFont);
		gtk_widget_draw(main_window, NULL);
	}
#endif
}

void
on_plusminus_font_ok_clicked                  (GtkButton       *button,
									 gpointer         user_data)
{
	on_plusminus_font_apply_clicked(button, user_data);
	gtk_widget_destroy(plusminus_font_dialog);
}

void
on_plusminus_font_cancel_clicked                  (GtkButton       *button,
										 gpointer         user_data)
{
	gtk_widget_destroy(plusminus_font_dialog);
}

gboolean
on_entry_L_button_release_event       (GtkWidget       *widget,
                                        GdkEventButton  *event,
                                        gpointer         user_data)
{
	if (algebraic_mode && !lift_needed)
		append_x("L");
	else
		process(XNL);
	return 0;
}

gboolean
on_entry_T_button_release_event        (GtkWidget       *widget,
                                        GdkEventButton  *event,
                                        gpointer         user_data)
{
	if (algebraic_mode && !lift_needed) {
		append_x("T");
	} else
		process(XNT);
	return 0;
}

gboolean
on_entry_Z_button_release_event       (GtkWidget       *widget,
                                        GdkEventButton  *event,
                                        gpointer         user_data)
{
	if (algebraic_mode && !lift_needed) {
		append_x("Z");
	} else
		process(XNZ);
	return 0;
}

gboolean
on_entry_Y_button_release_event       (GtkWidget       *widget,
                                        GdkEventButton  *event,
                                        gpointer         user_data)
{
	if (algebraic_mode && !lift_needed) {
		append_x("ans ");
	} else
		process(XNY);
	return 0;
}

void
on_annuity_in_advance_activate         (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	process(BEGIN);
}

void
on_fixed_point_numbering_activate      (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	process(FIX);
}

void
on_engineering_numbering_activate      (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	process(ENG);
}

void
on_scientific_numbering_activate        (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	process(SCIFORMAT);
}


void
on_places_activate                    (GtkMenuItem     *menuitem,
									   gpointer         user_data)
{
	process(PLACES);
}

static void
showWidget(char *name) {
	gpointer g;

	g = gtk_object_get_data(GTK_OBJECT (main_window), name);
	if (g)
		gtk_widget_show(g);
	else
		fprintf(stderr, "gdcalc: Can't find widget %s\n", name);
}

static void
hideWidget(char *name) {
	gpointer g;

	g = gtk_object_get_data(GTK_OBJECT (main_window), name);
	if (g)
		gtk_widget_hide(g);
	else
		fprintf(stderr, "gdcalc: Can't find widget %s\n", name);
}

void
on_rpn_activate                        (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	/* gtk_entry_set_editable(entryX, 0); */
	/* GTK_WIDGET_UNSET_FLAGS (entryX, GTK_CAN_FOCUS); */

	showWidget("Enter");
	hideWidget("LeftBrace");
	hideWidget("RightBrace");
	hideWidget("Equals");
		
	process(RPN);
}

void
on_algebraic_activate                  (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	/* gtk_entry_set_editable(entryX, 1); */
	/* GTK_WIDGET_SET_FLAGS (entryX, GTK_CAN_FOCUS); */
	gtk_widget_grab_focus(GTK_WIDGET(entryX));

	hideWidget("Enter");
	showWidget("LeftBrace");
	showWidget("RightBrace");
	showWidget("Equals");
		
	process(ALGEBRAIC);
}

gboolean
on_eval_key_press_event                (GtkWidget       *widget,
                                        GdkEventKey     *event,
                                        gpointer         user_data)
{

	int inval;
	GtkWidget *eval_ok;

	inval = event->keyval;
	/* printf("on_eval_key_press_event: inval = %d\n", inval); */

	if (inval == GDK_Return) {
		gtk_signal_emit_stop_by_name(GTK_OBJECT (widget), "key_press_event");
		eval_ok = gtk_object_get_data(GTK_OBJECT (eval_dialog), _("eval_ok"));
		gtk_button_clicked(GTK_BUTTON(eval_ok));
		return TRUE;
	}
	return FALSE;
}

static void
cleanup(char *buf, int i) {
	long lval;
	double dval;
	char *s, *d;

	parseBuffer(buf, &lval, &dval);
	fmt_base(buf, lval, dval);
	/* remove leading whitespace: */
	for (s = buf; *s && isspace(*s); s++) 
		;
	if (s > buf) {
		for (d = buf; *s; )
			*d++ = *s++;
		*d = 0;
	}
}

/* Yes this is more ugliness - due to ugliness in the way gtk handles
 * copy/paste etc. We get here every time text is put into entryX. If
 * we are doing it from dCalc we set the global flag (!)
 * insertedTextIsFromDcalc. Otherwise we assume we are doing a
 * paste. We also get a chance to tidy up the paste (syncronise with
 * dCalc's understanding of the contents of entryX) in the _port
 * routine. Yuck.
 */
#define MAX_PASTE 45
char pasteBuf[MAX_PASTE];
void
on_entry_X_insert_text(GtkEditable     *editable,
					   gchar           *new_text,
					   gint             new_text_length,
					   gint            *position,
					   gpointer         user_data)
{
	int i;
	char *s;

	if (insertedTextIsFromDcalc)
		return;

	i = (new_text_length > MAX_PASTE)? MAX_PASTE: new_text_length;
	strncpy(pasteBuf, (char *)new_text, i);
	pasteBuf[i] = 0;

	if (algebraic_mode) {
		if (liftStack()) {
			set_x("");
		}
		append_x(pasteBuf);
	} else {
		cleanup(pasteBuf, 0);

		if (pasteBuf[0] == 0)
			return;

		for (s = pasteBuf; *s; s++) {
			process(toupper(*s));
		}
	}
	strcpy(pasteBuf, get_x());
}

void
on_entry_X_insert_text_post            (GtkEditable     *editable,
                                        gchar           *new_text,
                                        gint             new_text_length,
                                        gint            *position,
                                        gpointer         user_data)
{

	if (insertedTextIsFromDcalc)
		return;

	if (pasteBuf[0])
		set_x(pasteBuf);
}

void
on_copy_activate                       (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	do_copy();
}


void
on_paste_activate                      (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{	
	do_paste();
}

void
on_main_window_destroy                 (GtkObject       *object,
                                        gpointer         user_data)
{
	process(QUIT);
}


/* For emacs: */
/* Local Variables: */
/* eval:(setq tab-width 4) */
/* End: */
